import logging
import os
import re

# 清空或创建日志文件
with open('app.log', 'w'):
    pass

# 创建一个logger对象
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)

# 创建一个文件处理器，用于写入日志文件
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.DEBUG)

# 创建一个控制台处理器，用于在控制台打印日志
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

# 创建一个格式器，定义日志格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 将格式器添加到处理器
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# 将处理器添加到logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)

#"/Users/mbc/code/JoyTale/JoyTale/Read/INReadQuickTopupAlertView.swift"
testPath = "/Users/mbc/code/JoyTale/JoyTale"
wordsMap = []
classes = []

allProperty = []
swiftElements = [
    # 关键字
    "class", "struct", "enum", "protocol", "func", "var", "let", "if",
    "else", "switch", "case", "default", "for", "in", "while", "repeat",
    "do", "try", "catch", "throw", "guard", "defer", "return", "break",
    "continue", "fallthrough", "as", "is", "nil", "self", "super", "true",
    "false", "associatedtype", "extension", "import", "init", "deinit",
    "subscript", "override", "where", "typealias", "fileprivate", "private",
    "internal", "public", "open", "static",

                    # 系统属性和变量
    "Element", "count", "isEmpty", "keys", "values", "lowercased", "uppercased",
    "max", "min", "infinity", "nan", "arguments",

                    # 系统函数
    "print", "fatalError", "assert", "min", "max", "abs", "round", "floor", "ceil",
    "arc4random",

                    # 常用系统类型
    "Int", "Double", "Float", "Bool", "String", "Character", "Array", "Dictionary",
    "Set", "Optional", "Result", "Error", "Date", "Data", "URL", "URLComponents",
    "Bundle", "FileManager", "NotificationCenter", "UserDefaults", "Timer", "DispatchQueue",

    # 常用系统协议
    "Equatable", "Comparable", "Hashable", "Codable", "Decodable", "Encodable",
    "CustomStringConvertible", "Sequence", "Collection", "ExpressibleByArrayLiteral",
    "ExpressibleByDictionaryLiteral",

    # 手动添加
    'tag', 'general', 'isSelected', 'title', 'width', 'width', 'size', 'text', 'offset',
]

def traverse_directory(func, path):
    if not os.path.isdir(path):
        logger.info(f"\n\n===== full_path: {path}")
        func(path)
        return

    # 列出路径中的所有文件和目录
    for entry in os.listdir(path):
        full_path = os.path.join(path, entry)
        # 如果是文件，则打印其路径
        if os.path.isfile(full_path):
            # print(full_path)
            logger.info(f"\n\n===== full_path: {full_path}")
            func(full_path)
        # 如果是目录，则递归遍历
        elif os.path.isdir(full_path):
            traverse_directory(func, full_path)

def get_name_mapper(propertyName):
    #字符串倒序
    return propertyName[::-1]

def get_class_property_fromFile(full_path):
    if full_path.endswith('.swift'):
        with open(full_path, 'r', encoding='utf-8') as f:
            content = f.read()
            # 匹配类定义的正则表达式
            class_pattern = r'class\s+(\w+)(?:\s*:\s*HandyJSON(?:\s*,\s*\w)*)\s*\{([\s\S]*?)\n\}'
            logger.info(f"===== class_pattern: {class_pattern}")
            def modifyClassContent(match):
                class_name = match.group(1)
                class_content = match.group(2)

                # 匹配属性
                properties = []
                # 匹配属性的正则表达式
                property_pattern = r'\b(var)\s+(\w+)\s*:?\s*([^{\n]+)?'
                def modifyPropertyName(match):
                    # 获取匹配结果中的属性名和数据类型
                    newName = get_name_mapper(match.group(2))
                    one = {
                        "name": match.group(2),  # 属性名
                        "newName": newName,
                    }
                    properties.append(one)
                    if one not in allProperty:
                        allProperty.append(one)

                    result = match.group(0).replace(match.group(2), newName)
                    # logger.debug(f"===== modify: old = {match.group(0)} --- new {result}")
                    return result

                # newClassContent = re.sub(property_pattern, modifyPropertyName, class_content)
                lines = class_content.split('\n')
                in_method = 0
                for i, line in enumerate(lines):
                    if '{' in line:
                        in_method += 1

                    if '}' in line:
                        in_method -= 1

                    if in_method == 0 and '{' not in line and '}' not in line:
                        # 不替换大括号内的变量
                        lines[i] = re.sub(property_pattern, modifyPropertyName, line)

                newClassContent = '\n'.join(lines)

                classes.append({
                    "name": class_name,
                    "properties": properties,
                    "path": full_path,
                })


                oldNames = list(map(lambda prop: prop["name"], properties))
                # 匹配属性的正则表达式
                instence_property_pattern = rf'(?<![.\w])({"|".join(re.escape(name) for name in oldNames)})\b'
                logger.info(f"===== instence_property_pattern = {instence_property_pattern}")

                def modifyInstencePropertyName(match):
                    # 获取匹配结果中的属性名和数据类型
                    oldName = match.group(1)
                    newName = oldName
                    for prop in properties:
                        if prop["name"] == oldName:
                            newName = prop["newName"]
                            break
                    logger.debug(f"===== modify instence: oldName: {match.group(0)} == newName: {newName}")
                    return newName

                newClassContent = re.sub(instence_property_pattern, modifyInstencePropertyName, newClassContent)

                return match.group(0).replace(class_content, newClassContent)

            content = re.sub(class_pattern, modifyClassContent, content, flags=re.DOTALL)

        with open(full_path, 'w', encoding='utf-8') as f:
            f.write(content)


def modify_extension_propertyName(full_path):
    if full_path.endswith('.swift'):
        with open(full_path, 'r', encoding='utf-8') as f:
            content = f.read()
            # 匹配类扩展的正则表达式
            classNames = list(map(lambda prop: prop["name"], classes))
            extension_pattern = rf'extension\s+({"|".join(re.escape(name) for name in classNames)})\s*{{([\s\S]*?)\n}}'
            logger.info(f"===== extension_pattern = {extension_pattern}")

            def modify_extension_content(match):
                class_name = match.group(1)
                class_content = match.group(2)

                classInfo = list(filter(lambda classInfo: classInfo["name"] == class_name, classes))[0]
                properties = classInfo["properties"]
                oldNames = list(map(lambda prop: prop["name"], properties))
                # 匹配属性的正则表达式
                property_pattern = rf'\b({"|".join(re.escape(name) for name in oldNames)})\b'
                def modifyPropertyName(match):
                    # 获取匹配结果中的属性名和数据类型
                    oldName = match.group(1)
                    newName = oldName
                    for prop in properties:
                        if prop["name"] == oldName:
                            newName = prop["newName"]
                            break
                    logger.debug(f"===== modify extension: old: {match.group(0)} == newName: {newName}")
                    return newName

                newClassContent = re.sub(property_pattern, modifyPropertyName, class_content)

                return match.group(0).replace(class_content, newClassContent)

            content = re.sub(extension_pattern, modify_extension_content, content, flags=re.DOTALL)

        with open(full_path, 'w', encoding='utf-8') as f:
            f.write(content)


# 修改变量名
def fix_instence_name(content, classes):
    for classinfo in classes:
        oldnames = list(map(lambda prop: prop["name"], classinfo["properties"]))
        newnames = list(map(lambda prop: prop["newName"], classinfo["properties"]))
        classname = classinfo["name"]

        instence_pattern = rf'\b(var|let)\s+(\w+)\s*((:\s*{classname}\b)|(=\s*{classname}\b))'
        # logger.info(f'==== instence_pattern = {instence_pattern}')
        # instence_pattern = rf'\b(var|let)\s+(\w+)\s*((:\s*{classname}(\?|!)?)|(=\s*{classname}\(\))|(:\s*{classname}\s*=\s*{classname}\(\)))'
        instence_Match = re.finditer(instence_pattern, content)

        instences = []
        for imatch in instence_Match:
            instences.append(imatch.group(2))

        # logger.info(f'==== all instences: {instences}')

        if instences.__len__() > 0:
            replace_pattern = rf'({"|".join(re.escape(inst) for inst in instences)})\s*\??\s*\.\s*({"|".join(re.escape(name) for name in oldnames)})\b'
            logger.info(f'==== replace_pattern = {replace_pattern}')

            def modifyPropertyName(match):
                oldname = match.group(2)
                newname = newnames[oldnames.index(oldname)]
                result = match.group(0).replace(oldname, newname)
                # logger.debug(f"===== wwwww: {match.group(0)} === {result}")
                return result

            content = re.sub(replace_pattern, modifyPropertyName, content)

    return content

# 修改方法内变量名
def fix_variable_inMethod_name(content, classes):
    allClassName = list(map(lambda prop: prop["name"], classes))

    # 更新的正则表达式，捕获更多细节
    method_pattern = r'(?:public\s+|private\s+|fileprivate\s+|internal\s+)?'  # 访问修饰符（可选）
    method_pattern += r'(?:override\s+)?'  # override关键字（可选）
    method_pattern += r'(?:static\s+)?'  # static关键字（可选）
    method_pattern += r'func\s+'  # func关键字
    method_pattern += r'(\w+)'  # 方法名 (捕获组1)
    # method_pattern += r'\s*\(((?:[^()]|\([^()]*\))*)\)'  # 参数列表 (捕获组2)
    method_pattern += rf'\s*\([^()]*\b(\w+)\s*:\s*({"|".join(re.escape(name) for name in allClassName)})[^()]*\)'
    method_pattern += r'(?:\s*->\s*([^{]+))?'  # 返回类型 (捕获组3，可选)
    method_pattern += r'\s*\{'  # 方法体开始
    # method_pattern += r'((?:[^{}]|\{(?:[^{}]|\{[^{}]*\}|\{(?:[^{}]|\{[^{}]*\})*\})*\})*)'  # 方法体 (捕获组4)
    method_pattern += r'((?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*\})*)'  # 方法体 (捕获组4)
    method_pattern += r'\s*\}'  # 方法体结束
    logger.info(rf"====== method_pattern = {method_pattern}")

    def modify_method_content(match):
        param_name = match.group(2)
        param_type = match.group(3)
        # method_body = match.group(5)
        logger.info(rf"====== match result = {match.group(0)}")

        for classinfo in classes:
            if classinfo["name"] == param_type:
                logger.info("=" * 50)
                logger.info(f"===== Method: {match.group(0)}")
                logger.info("=" * 50)

                oldnames = list(map(lambda prop: prop["name"], classinfo["properties"]))
                newnames = list(map(lambda prop: prop["newName"], classinfo["properties"]))

                model_pattern = rf'\b{param_name}\.({"|".join(re.escape(name) for name in oldnames)})'
                logger.info(rf"====== model_pattern = {model_pattern}")

                def modifyPropertyName(match):
                    oldname = match.group(1)
                    newname = newnames[oldnames.index(oldname)]
                    result = match.group(0).replace(oldname, newname)
                    logger.debug(f"===== wwwww: {match.group(0)} === {result}")
                    return result

                return re.sub(model_pattern, modifyPropertyName, match.group(0))

        return match.group(0)

    content = re.sub(method_pattern, modify_method_content, content, flags=re.DOTALL)

    return content


def modify_instence_property_inFile(full_path):
    if full_path.endswith('.swift'):
        with open(full_path, 'r', encoding='utf-8') as f:
            content = f.read()

            content = fix_instence_name(content, classes)
            # content = fix_instencelist_name(content, classes)
            content = fix_variable_inMethod_name(content, classes)

        with open(full_path, 'w', encoding='utf-8') as f:
            f.write(content)


def modify_other_property_name(full_path):
    if full_path.endswith('.swift'):
        with open(full_path, 'r', encoding='utf-8') as f:
            content = f.read()

            property_pattern = rf'\b\w+\??\.({"|".join(re.escape(name["name"]) for name in allProperty)})\b[^\(]*'

            def modifyPropertyName(match):
                oldname = match.group(1)
                newname = [name for name in allProperty if name["name"] == oldname][0]["newName"]
                result = match.group(0).replace(oldname, newname)
                logger.debug(f"===== wwwww: {match.group(0)} === {result}")
                return result

            content = re.sub(property_pattern, modifyPropertyName, content)

        with open(full_path, 'w', encoding='utf-8') as f:
            f.write(content)

# xxxxx
traverse_directory(get_class_property_fromFile, testPath)

# for classinfo in  classes:
#     print(classinfo)

logger.info(f"===== swift_classes count: {classes.__len__()}")

traverse_directory(modify_extension_propertyName, testPath)

traverse_directory(modify_instence_property_inFile, testPath)

logger.info(f"===== allProperty count: {allProperty.__len__()}")
allProperty = [item for item in allProperty if item["name"] not in swiftElements]
logger.info(f"===== allProperty count: {allProperty.__len__()}")

# traverse_directory(modify_other_property_name, testPath)

